import { logWarn } from "../utils/Log";
import { createTerrain, noTerrain } from "../utils/Terrain";
import { defaultToken } from "../const/Token";
import { isNumber, isString } from "../utils/Util";
import { createLayer } from "../utils/Layer";

let DefaultOptions = {
  animation: false, // 是否显示动画控件
  baseLayerPicker: false,  // 是否显示图层选择控件
  fullscreenButton: false,  // 是否显示全屏控件
  vrButton: false, // 是否显示VR控件
  geocoder: false,  // 是否显示地名查找控件
  homeButton: false,  // 是否显示返回默认视图控件
  infoBox: false,   // 是否显示点击要素之后显示的信息
  sceneModePicker: false,  // 是否显示切换2D、3D控件
  selectionIndicator: false,  // 是否显示选取指示器控件
  timeline: false,  // 是否显示时间轴控件
  navigationHelpButton: false,  // 是否显示帮助信息控件
  navigationInstructionsInitiallyVisible: false,  // 是否显示鼠标控制提示
  scene3DOnly: true,  // 所有几何实例以3D模式绘制以节约GPU资源
  shouldAnimate: true,  // 是否自动播放动画
}

export class Map {
  constructor(id, options = {}) {
    this.options = options;
    this._viewer = this._createViewer(id, options);

    // 图层缓存
    this._layerCache = {};
    //  处理地形
    this._initTerrain();

    // 处理图层
    this._initLayers();
  }

  get viewer () {
    return this._viewer;
  }

  /**
   * 获取将在地球上渲染的ImageryLayer图像图层的集合
   *
   * @readonly
   * @memberof Map
   */
  get imageryLayers () {
    return this._viewer.imageryLayers
  }

  get hasTerrain () {
    return Boolean(this._viewer.terrainProvider._layers)
  }
  set hasTerrain (val) {
    if (val) {
      this._viewer.terrainProvider = createTerrain(this.options.terrain.url).then(res => {
        this._viewer.terrainProvider = res;
      })
    } else {
      this._viewer.terrainProvider = noTerrain()
    }
  }

  // =========== 方法 ===========
  _createViewer (id, options) {
    if (!id || !document.getElementById(id)) {
      logWarn(`地图容器不存在，id：${id}`);
      return;
    }

    Cesium.Ion.defaultAccessToken = defaultToken

    let viewerOptions = Object.assign({}, DefaultOptions, options.scene);
    let viewer = new Cesium.Viewer(id, viewerOptions);
    //去除版权信息
    viewer._cesiumWidget._creditContainer.style.display = "none";
    return viewer;
  }

  // 处理地形
  async _initTerrain () {
    if (this.options.terrain && this.options.terrain.show) {
      const terrainProvider = await createTerrain(this.options.terrain.url)
      this._viewer.terrainProvider = terrainProvider
    }
  }

  // 处理图层
  async _initLayers () {
    this.options.basemaps = this.options.basemaps || [];
    this.options.layers = this.options.layers || [];

    this._layerIndex = undefined;
    this._layerIndexs = [];

    if (this.options.basemaps.length === 0) {
      this._viewer.scene.imageryLayers.add(
        Cesium.ImageryLayer.fromProviderAsync(
          Cesium.TileMapServiceImageryProvider.fromUrl(Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII'))
        )
      );
    }

    // 按zIndex排序
    this.options.basemaps.sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));
    this.options.layers.sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));

    // 添加底图数据
    this.options.basemaps.forEach((item) => {
      this._commonLayer(item);
    });

    // 底图上叠加图层数据
    this.options.layers.forEach((item) => {
      this._commonLayer(item);
    });
  }

  _commonLayer (item) {
    if (!item.id) {
      item.id = this.getCustomLayerId();
    }
    this._layerIndex = item.id;
    const layer = createLayer(item);
    if (!layer) return;
    if (item.show) {
      this.addLayer(layer);
    }
  }
  /**
 * 获取图层ID值，按顺序取值。
 * @return {Int} 图层ID
 */
  getCustomLayerId () {
    while (this._layerIndexs.indexOf(this._layerIndex) != -1) {
      this._layerIdx++
    }
    this._layerIndexs.push(this._layerIndex)
    return this._layerIndex
  }

  /**
   * 添加图层到地图上
   * @param {*} layer 图层对象
   * @returns 
   */
  addLayer (layer) {
    if (!layer) return;
    layer._onAdd(this);  
    if (this._layerCache[layer.id] && this._layerCache[layer.id] !== layer) {
      layer.id = this.getCustomLayerId()
      logWarn('addLayer:图层id存在冲突，已重新赋值id', layer)
    }
    this._layerCache[layer.id] = layer
    return this

  }

  removeLayer (layer, hasDestory) {
    if (!layer) {
      return this
    }

    if (isString(layer) || isNumber(layer)) {
      //直接传入id
      layer = this._layerCache[layer]
      if (!layer) {
        return this
      }
    }
    layer._removedHook()

    delete this._layerCache[layer.id]

    if (hasDestory) {
      layer.destroy()
    }
  }
}